﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using ToolKit.Mvvm.Attributes;
using ToolKit.Mvvm.Enums;
using ToolKit.Mvvm.Extensions;
using ToolKit.Mvvm.Interfaces;

namespace ToolKit.Mvvm
{
    public class Container : IContainer
    {
        public static Container Default { get; } = new Lazy<Container>().Value;

        private readonly ConcurrentDictionary<Type, ConstructorInfo> _constructors = new ConcurrentDictionary<Type, ConstructorInfo>();
        private readonly ConcurrentDictionary<Type, Dictionary<string, Delegate>> _factories = new ConcurrentDictionary<Type, Dictionary<string, Delegate>>();
        private readonly ConcurrentDictionary<Type, Dictionary<string, object>> _instancesRegistry = new ConcurrentDictionary<Type, Dictionary<string, object>>();
        private readonly ConcurrentDictionary<Type, Type> _interfaceMaps = new ConcurrentDictionary<Type, Type>();
        private readonly object[] _emptyArguments = new object[0];
        private readonly string _defaultKey = Guid.NewGuid().ToString();
        public IModuleManager ModuleManager { get; } = new ModuleManager();
        public Assembly MainAssembly { get; set; }


        /// <summary>
        /// No1.以接口的形式注册类型到IOC容器
        /// 调用示例:container.Register<IUserRepository, UserRepository>();
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TImplementation"></typeparam>
        public void Register<TInterface, TImplementation>() where TInterface : class where TImplementation : class, TInterface
        {
            Type interfaceType = typeof(TInterface);//接口的Type
            Type serviceType = typeof(TImplementation);//子类的Type
            if (!_interfaceMaps.ContainsKey(interfaceType))
            {
                _interfaceMaps.TryAdd(interfaceType, serviceType);
                _constructors.TryAdd(serviceType, serviceType.GetConstructorInfo(_interfaceMaps));
            }
            Func<TInterface> factory = Resolve<TInterface>;
            DoRegister(interfaceType, factory, _defaultKey);
        }

        private void DoRegister<T>(Type interfaceType, Func<T> factory, string key)
        {
            if (_factories.ContainsKey(interfaceType))
            {
                if (_factories[interfaceType].ContainsKey(key))
                    return;
                _factories[interfaceType].TryAdd(key, factory);
            }
            else
            {
                var list = new Dictionary<string, Delegate>();
                list.TryAdd(key, factory);
                _factories.TryAdd(interfaceType, list);
            }
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private T Resolve<T>()
        {
            var interfaceType = typeof(T);
            var constructor = _constructors.ContainsKey(interfaceType) ? _constructors[interfaceType] : interfaceType.GetConstructorInfo(_interfaceMaps);
            var parameterInfos = constructor.GetParameters();
            if (parameterInfos.Length == 0)
            {
                return (T)constructor.Invoke(_emptyArguments);//创建无参对象
            }

            var parameters = new object[parameterInfos.Length];
            foreach (var item in parameterInfos)
            {
                parameters[item.Position] = GetService(item.ParameterType);//获取参数对象
            }

            return (T)constructor.Invoke(parameters);//创建有参对象
        }

        /* DynamicallyAccessedMembers:指示指定 Type 上的某些成员以动态方式进行访问*/

        /// <summary>
        /// No2.将独立类注册到IOC容器
        /// 调用示例:
        /// container.Register<MainWindow>();
        /// container.Register<MainViewModel>();
        /// </summary>
        /// <typeparam name="TImplementation"></typeparam>
        public void Register<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>() where TImplementation : class
        {
            Type type = typeof(TImplementation);
            Register(type);
        }

        public void Register([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type)
        {
            if (!_interfaceMaps.ContainsKey(type))
            {
                _interfaceMaps.TryAdd(type, type);
                _constructors.TryAdd(type, type.GetConstructorInfo(_interfaceMaps));
            }
            Func<Type, object> factory = Resolve;
            //Func<object> func = delegate
            //{
            //    var constructor = _constructors.ContainsKey(type) ? _constructors[type] : type.GetConstructorInfo(_interfaceMaps);
            //    var parameterInfos = constructor.GetParameters();
            //    if (parameterInfos.Length == 0)
            //    {
            //        return constructor.Invoke(_emptyArguments);
            //    }

            //    var parameters = new object[parameterInfos.Length];
            //    foreach (var item in parameterInfos)
            //    {
            //        parameters[item.Position] = GetService(item.ParameterType);
            //    }

            //    return constructor.Invoke(parameters);
            //};

            if (_factories.ContainsKey(type))
            {
                if (_factories[type].ContainsKey(_defaultKey))
                    return;
                _factories[type].TryAdd(_defaultKey, factory);
            }
            else
            {
                var list = new Dictionary<string, Delegate>();
                list.TryAdd(_defaultKey, factory);
                _factories.TryAdd(type, list);
            }
        }

        /// <summary>
        /// No3.通过特性标识类型，以接口的形式全自动注册类型到IOC容器
        /// </summary>
        /// <param name="interfaceType"></param>
        /// <param name="implementationType"></param>
        public void Register(Type interfaceType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type serviceType)
        {
            if (!_interfaceMaps.ContainsKey(interfaceType))
            {
                _interfaceMaps.TryAdd(interfaceType, serviceType);
                _constructors.TryAdd(serviceType, serviceType.GetConstructorInfo(_interfaceMaps));
            }
            Func<Type, object> factory = Resolve;
            //Func<object> func = delegate 
            //{
            //    var constructor = _constructors.ContainsKey(interfaceType) ? _constructors[interfaceType] : interfaceType.GetConstructorInfo(_interfaceMaps);
            //    var parameterInfos = constructor.GetParameters();
            //    if (parameterInfos.Length == 0)
            //    {
            //        return constructor.Invoke(_emptyArguments);
            //    }

            //    var parameters = new object[parameterInfos.Length];
            //    foreach (var item in parameterInfos)
            //    {
            //        parameters[item.Position] = GetService(item.ParameterType);
            //    }

            //    return constructor.Invoke(parameters);
            //};

            if (_factories.ContainsKey(interfaceType))
            {
                if (_factories[interfaceType].ContainsKey(_defaultKey))
                    return;
                _factories[interfaceType].TryAdd(_defaultKey, factory);
            }
            else
            {
                var list = new Dictionary<string, Delegate>();
                list.TryAdd(_defaultKey, factory);
                _factories.TryAdd(interfaceType, list);
            }
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private object Resolve(Type type)
        {
            var constructor = _constructors.ContainsKey(type) ? _constructors[type] : type.GetConstructorInfo(_interfaceMaps);
            var parameterInfos = constructor.GetParameters();
            if (parameterInfos.Length == 0)
            {
                return constructor.Invoke(_emptyArguments);
            }

            var parameters = new object[parameterInfos.Length];
            foreach (var item in parameterInfos)
            {
                parameters[item.Position] = GetService(item.ParameterType);
            }

            return constructor.Invoke(parameters);
        }

        public object GetService(string viewName)
        {
            Dictionary<string, object> instances = null;
            var view = _instancesRegistry.Where(t => t.Key.Name == viewName);
            if (view.Count() > 0)
            {
                instances = view.FirstOrDefault().Value;
                return instances.Values.FirstOrDefault();
            }
            else
            {
                instances = new Dictionary<string, object>();
                var factory = _factories.FirstOrDefault(t => t.Key.Name == viewName);
                var interfaceType = factory.Key;
                if (object.ReferenceEquals(interfaceType, null) || object.ReferenceEquals(factory, null))
                {
                    throw new NullReferenceException($"[{viewName}] 没有在IOC中注册");
                }
                var key = _defaultKey;
                object instance = null;

                if (_factories.ContainsKey(interfaceType) && _factories[interfaceType].ContainsKey(key))
                {
                    var t = _factories[interfaceType][key];
                    var p = t.Method.GetParameters();
                    if (p.Length == 1)
                    {
                        instance = _factories[interfaceType][key].DynamicInvoke(interfaceType);
                    }
                    else
                    {
                        instance = _factories[interfaceType][key].DynamicInvoke(null);
                    }
                }
                else if (_factories[interfaceType].ContainsKey(_defaultKey))
                {
                    var t = _factories[interfaceType][key];
                    var p = t.Method.GetParameters();
                    if (p.Length == 1)
                    {
                        instance = _factories[interfaceType][_defaultKey].DynamicInvoke(interfaceType);
                    }
                    else
                    {
                        instance = _factories[interfaceType][_defaultKey].DynamicInvoke(null);
                    }
                }

                if (instances != null)
                {
                    var lifetime = GetLifetime(instance.GetType());
                    if (lifetime == null || lifetime == Lifetime.Singleton)
                    {
                        _instancesRegistry.TryAdd(interfaceType, instances);
                        instances.Add(key, instance);
                    }
                    else
                    {
                        //瞬态注册 do nothing
                    }
                }

                //DataContext绑定处理
                BindingDataContext(instance);

                return instance;
            }
        }

        /// <summary>
        /// DataContext绑定处理
        /// </summary>
        /// <param name="instance"></param>
        private void BindingDataContext(object instance)
        {
            if (instance == null) return;
            var viewAttribute = GetViewAttribute(instance);
            if (viewAttribute != null)
            {
                BindViewModel(instance);
            }
        }

        /// <summary>
        /// 获取T的实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetService<T>()
        {
            return (T)GetService(typeof(T));
        }

        /// <summary>
        /// 获取Type的实例
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public object GetService(Type serviceType)
        {
            return DoGetService(serviceType, _defaultKey);
        }


        private object DoGetService(Type interfaceType, string key)
        {
            key = string.IsNullOrEmpty(key) ? _defaultKey : key;
            Dictionary<string, object> instances = null;
            if (!_instancesRegistry.ContainsKey(interfaceType))
            {
                instances = new Dictionary<string, object>();

                //_instancesRegistry.TryAdd(interfaceType, instances);

                //var lifetime = GetLifetime(interfaceType);
                //if (lifetime == null || lifetime == Lifetime.Singleton)
                //{
                //    instances = new Dictionary<string, object>();
                //    _instancesRegistry.TryAdd(interfaceType, instances);
                //}
                //else
                //{
                //    var l = lifetime;
                //}
            }
            else
            {
                instances = _instancesRegistry[interfaceType];
            }

            if (instances != null && instances.ContainsKey(key))
            {
                return instances[key];
            }

            object instance = null;
            if (_factories.ContainsKey(interfaceType) && _factories[interfaceType].ContainsKey(key))
            {
                var t = _factories[interfaceType][key];
                var p = t.Method.GetParameters();
                if (p.Length == 1)
                {
                    instance = _factories[interfaceType][key].DynamicInvoke(interfaceType);
                }
                else
                {
                    instance = _factories[interfaceType][key].DynamicInvoke(null);
                }
            }
            else if (_factories[interfaceType].ContainsKey(_defaultKey))
            {
                var t = _factories[interfaceType][key];
                var p = t.Method.GetParameters();
                if (p.Length == 1)
                {
                    instance = _factories[interfaceType][_defaultKey].DynamicInvoke(interfaceType);
                }
                else
                {
                    instance = _factories[interfaceType][_defaultKey].DynamicInvoke(null);
                }
            }

            if (instances != null)
            {
                var lifetime = GetLifetime(instance.GetType());
                if (lifetime == null || lifetime == Lifetime.Singleton)
                {
                    _instancesRegistry.TryAdd(interfaceType, instances);
                    instances.Add(key, instance);
                }
                else
                {
                    //瞬态注册 do nothing
                }
            }

            //DataContext绑定处理
            BindingDataContext(instance);
            //实现自动属性通知
            AutoNotify(instance);

            return instance;
        }


        public Lifetime? GetLifetime(Type type)
        {
            var attribute = type.GetCustomAttribute<DependenceInjectionAttribute>();
            if (attribute != null)
            {
                return attribute.Lifetime;
            }
            return null;
        }

        private void AutoNotify(object instance)
        {
            Type serviceType = instance.GetType();
            var list = serviceType.GetProperties();
            foreach (PropertyInfo property in list)
            {                
                if (property.CustomAttributes.Any(p => p.AttributeType == typeof(AutoNotifyAttribute)))
                {

                }
            }
        }

        public void BindViewModel(object view)
        {
            /*
             * 在C#中，InvariantCulture是CultureInfo类中常用的一个属性。它表示一个固定不变的区域性对象，
             * 用于在不考虑当前操作系统的区域设置的情况下执行字符串操作。
             * 使用InvariantCulture的好处是可以确保在不同的区域设置下，字符串操作的结果是一致的。
             * 例如，使用InvariantCulture进行字符串比较时，不会受到不同区域设置下的排序规则的影响，而是按照固定的规则进行比较。
             */

            var viewType = view.GetType();
            var viewName = viewType.FullName;
            viewName = viewName.Replace(".Views.", ".ViewModels.");
            var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
            var suffix = viewName.EndsWith("View") ? "Model" : "ViewModel";
            var viewModelName = string.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", viewName, suffix, viewAssemblyName);
            var viewModelType = Type.GetType(viewModelName);
            var viewModel = GetService(viewModelType);
            if (view is FrameworkElement element)
            {
                element.DataContext = element.DataContext ?? viewModel;
            }
        }

        public ViewAttribute GetViewAttribute(object instance)
        {
            var serviceType = instance.GetType();
            return serviceType.GetCustomAttribute<ViewAttribute>();
        }

        public void Register(List<Type> types)
        {
            if (types == null || types.Count == 0)
                return;

            foreach (Type serviceType in types)
            {
                //获取子类的注册接口
                var attributes = serviceType.GetDependenceInjectionAttributes();

                foreach (var attribute in attributes)
                {
                    if (attribute.InterfaceTypes.Length == 0)
                    {
                        Register(serviceType);//注册子类
                    }
                    else
                    {
                        foreach (var interfaceType in attribute.InterfaceTypes)
                        {
                            Register(interfaceType, serviceType);
                        }
                    }
                }
            }
        }
    }
}
